import * as Koa from 'koa';
import { Transaction } from 'tiny-entity2';
import { Guid, route, RouteOptionsBase, RouteOptionsVerify, ServiceManager, UsingLock } from "../../common";
import { ServiceException } from '../../common/excpetion';
import { ApiDataContext } from '../../domain/apiDataContext';
import { User } from '../../domain/models/user';
import { Account } from '../../domain/models/account';
import { UserService } from '../../service/UserService';
import { OrganizationTreeService } from '../../service/organizationTreeService';
import { OrganizationTree } from '../../domain/models/organizationTree';
import { AccountService } from '../../service/accountService';
import moment = require('moment');
import md5 = require('md5');

const userSvr = ServiceManager.Current.GetService<UserService>('UserService');
const orzTreeSvr = ServiceManager.Current.GetService<OrganizationTreeService>('OrganizationTreeService');
const accSvr = ServiceManager.Current.GetService<AccountService>('AccountService');

class UserController {
    @route(new RouteOptionsBase('GET', '/api/user'))
    async queryUsers(ctx: Koa.Context, next) {
        let rootOrgId = ctx.headers['orgid'];
        let params = ctx.query;
        params.organizationId = rootOrgId;

        let users = await userSvr.QueryUser(params);
        let userids: string = "";
        users.list.forEach(x => {
            if (userids.indexOf(x.id) <= -1) {
                userids += x.id + ",";
            }
        });

        let orgtree: OrganizationTree[] = await orzTreeSvr.QueryOrganizationTree({ organizationId: rootOrgId, objectIds: userids });
        let departmentids: string = "";
        orgtree.forEach(x => {
            if (departmentids.indexOf(x.parentId) <= -1) {
                departmentids += x.parentId + ",";
            }
        });
        let deptree: OrganizationTree[] = await orzTreeSvr.QueryOrganizationTree({ organizationId: rootOrgId, objectIds: departmentids });

        users.list.forEach(x => {
            let usertreenode=deptree.find(xx=>xx.objectId==x.id);
            if(usertreenode)
            {
               let deptreenode=deptree.find(xxx=>xxx.id==usertreenode.parentId);
               if(deptreenode)
               {
                  x.depName=deptreenode.nodeName;
               }
            }
        });

        ctx.response.body = users;

        await next();
    }
    @route(new RouteOptionsBase('GET', '/api/user/:id'))
    async getUserInfoById(ctx: Koa.Context, next) {
        let rootOrgId = ctx.headers['orgid'];
        let id = ctx.params.id;
        let data = await userSvr.GetUserById(id);

        let orgtrees: OrganizationTree[] = await orzTreeSvr.QueryOrganizationTree({ objectName: data.ClassName(), objectId: id, organizationId: rootOrgId });
        data.orgTree = <OrganizationTree>{};
        if (orgtrees && orgtrees.length > 0) {
            data.orgTree = orgtrees[0];
        }
        let acc: Account = await accSvr.GetAccountById(data.accountId);
        data.acc = acc;

        ctx.response.body = data;
        await next();
    }
    @route(new RouteOptionsBase('POST', '/api/user'))
    async createUser(ctx: Koa.Context, next) {
        let rootOrgId = ctx.headers['orgid'];
        let user: User = ctx.request.body;
        user.orgTree.organizationId = rootOrgId;
        user.organizationId = rootOrgId;

        checkData(user);

        user.id = Guid.GetGuid();
        user.isDelete = false;
        var today = Date.now();
        user.createTime = today;//moment().subtract(days, 'days').unix()

        let orgTree = new OrganizationTree();
        orgTree.id = Guid.GetGuid();
        if (rootOrgId) {
            orgTree.organizationId = rootOrgId;
        }

        let acc: Account = new Account();
        acc.id = Guid.GetGuid();
        acc.username = user.employeeNo;
        acc.password = md5(user.acc.password);
        acc.isDelete = false;

        await Transaction(new ApiDataContext(), async datactx => {
            let result = new User();
            acc.verifyMode = result.ClassName();
            let accResult: Account = await accSvr.CreateAccount(acc);
            user.accountId = acc.id;

            result = await userSvr.CreateUser(user, datactx);
            result.acc = accResult;

            orgTree.objectId = result.id;
            orgTree.objectName = result.ClassName();
            orgTree.nodeName = result.name;
            orgTree.parentId = user.orgTree.parentId;
            orgTree.id = Guid.GetGuid();
            orgTree.isDelete = false;
            result.orgTree = await orzTreeSvr.CreateorganizationTree(orgTree, datactx);

            ctx.response.body = result;
        });

        await next();
    }
    @route(new RouteOptionsBase('PUT', '/api/user'))
    async updateUser(ctx: Koa.Context, next) {
        let rootOrgId = ctx.headers['orgid'];
        let user: User = ctx.request.body;
        user.orgTree.organizationId = rootOrgId;
        user.organizationId = rootOrgId;

        if (!user.id) {
            throw new ServiceException('id 不能为空！');
        }
        if (!user.acc.id) {
            throw new ServiceException('账号Id 不能为空！');
        }
        checkData(user);

        let orgTree: OrganizationTree = user.orgTree;
        if (rootOrgId) {
            orgTree.organizationId = rootOrgId;
        }

        let acc: Account = user.acc;
        acc.username = user.employeeNo;

        await UsingLock(acc.id, async () => {
            await Transaction(new ApiDataContext(), async datactx => {
                let result = new User();
                acc.verifyMode = result.ClassName();
                let accData = await accSvr.GetAccountById(acc.id);

                if (acc.password && acc.password.length > 0 && acc.password != accData.password) {
                    acc.password = md5(acc.password);
                }
                
                accData.username=acc.username?acc.username:accData.username;
                accData.verifyMode=acc.verifyMode?acc.verifyMode:accData.verifyMode;
                accData.isDelete=acc.isDelete?acc.isDelete:accData.isDelete;
                accData.password=acc.password?acc.password:accData.password;

                let accResult: Account = await accSvr.UpdateAccount(accData);

                let userData = await userSvr.GetUserById(user.id);

                userData.employeeNo=user.employeeNo?user.employeeNo:userData.employeeNo;
                userData.organizationId=user.organizationId?user.organizationId:userData.organizationId;
                userData.accountId=user.accountId?user.accountId:userData.accountId;
                userData.name=user.name?user.name:userData.name;
                userData.gender=user.gender?user.gender:userData.gender;
                userData.createTime=user.createTime?user.createTime:userData.createTime;
                userData.phone=user.phone?user.phone:userData.phone;
                userData.birth=user.birth?user.birth:userData.birth;
                userData.status=user.status?user.status:userData.status;
                userData.position=user.position?user.position:userData.position;
                userData.isDelete=user.isDelete?user.isDelete:userData.isDelete;
                userData.headerPhoto=user.headerPhoto?user.headerPhoto:userData.headerPhoto;
                userData.idCard=user.idCard?user.idCard:userData.idCard;

                result = await userSvr.UpdateUser(userData, datactx);

                result.acc = accResult;

                orgTree.objectId = result.id;
                orgTree.objectName = result.ClassName();
                orgTree.nodeName = result.name;
                orgTree.parentId = user.orgTree.parentId;
                orgTree.id = user.orgTree.id;

                let orgTreeData = await orzTreeSvr.GetOrganizationTreeById(orgTree.id);
                orgTreeData.organizationId=orgTree.organizationId?orgTree.organizationId:orgTreeData.organizationId;
                orgTreeData.isRoot=orgTree.isRoot?orgTree.isRoot:orgTreeData.isRoot;
                orgTreeData.parentId=orgTree.parentId?orgTree.parentId:orgTreeData.parentId;
                orgTreeData.objectId=orgTree.objectId?orgTree.objectId:orgTreeData.objectId;
                orgTreeData.objectName=orgTree.objectName?orgTree.objectName:orgTreeData.objectName;
                orgTreeData.nodeName=orgTree.nodeName?orgTree.nodeName:orgTreeData.nodeName;
                orgTreeData.isDelete=orgTree.isDelete?orgTree.isDelete:orgTreeData.isDelete;

                result.orgTree = await orzTreeSvr.UpdateorganizationTree(orgTreeData, datactx);
                ctx.response.body = result;
            });
        })

        await next();
    }
    @route(new RouteOptionsBase('DELETE', '/api/user/:id'))
    async deleteUser(ctx: Koa.Context, next) {
        let rootOrgId = ctx.headers['orgid'];
        let id = ctx.params.id;

        if (!id) {
            throw new ServiceException('id 不能为空！', 'not_be_null');
        }
        let user = await userSvr.GetUserById(id);
        user.isDelete = true;

        ctx.response.body = await UsingLock(user.id, async () => {
            await Transaction(new ApiDataContext(), async datactx => {
                let userData = await userSvr.GetUserById(user.id);
                userData.ConverToEntity(user);

                let account: Account = await accSvr.GetAccountById(userData.accountId);
                account.isDelete = true;
                await accSvr.UpdateAccount(account, datactx);

                let result = await userSvr.UpdateUser(user, datactx);
                let acctrees = await orzTreeSvr.QueryOrganizationTree({ objectId: user.id, organizationId: rootOrgId });
                if (acctrees && acctrees.length > 0) {
                    user.orgTree = acctrees[0];
                    user.orgTree.isDelete = true;
                    await orzTreeSvr.UpdateorganizationTree(user.orgTree, datactx);
                }
                return result;
            });
        })
        // await UsingLock(id, async () => {
        //     let result = await userSvr.DeleteUser(user);
        //     ctx.response.body =result;
        // })
        await next();
    }
}

const checkData = (data: User) => {
    if (!data.name) {
        throw new ServiceException('未填写用户名称！');
    }
    if (!data.employeeNo) {
        throw new ServiceException('未填写用户工号！');
    }
    if (!data.organizationId) {
        throw new ServiceException('未传入所属组织编号！');
    }

    if (!data.orgTree.organizationId) {
        throw new ServiceException('未传入根组织编号！');
    }
}